package com.star.learn.excel.service;

import com.alibaba.excel.EasyExcel;
import com.alibaba.excel.ExcelReader;
import com.alibaba.excel.read.listener.ReadListener;
import com.alibaba.excel.read.metadata.ReadSheet;
import com.star.learn.excel.domain.Student;
import com.star.learn.excel.util.ExcelUtil;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.util.DigestUtils;

import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.CompletableFuture;
import java.util.concurrent.Executor;

@Service
@Slf4j
public class ExcelService {

    @Value("${excel.files-dir}")
    private String filesDir;

    // 注入 RedisMetadataService
    @Resource
    private RedisMetadataService redisMetadataService;

    @Resource
    private RabbitMQProducerService rabbitMQProducerService;

    @Resource(name = "taskExecutor")
    private Executor taskExecutor;

    public void processExcelFiles() {
        // 从配置读取目录
        File folder = new File(filesDir);
        File[] files = folder.listFiles((dir, name) -> name.endsWith(".xls") || name.endsWith(".xlsx"));

        if (files == null || files.length == 0) {
            log.info("未找到待处理的 Excel 文件在目录: {}", filesDir);
            return;
        }
        log.info("发现 {} 个待处理的 Excel 文件.", files.length);
        // 记录总开始时间（用于耗时统计）
        long startTime = System.currentTimeMillis();
        List<CompletableFuture<Void>> fileFutures = new ArrayList<>(); // 用于存储每个文件处理任务的 CompletableFuture
        for (File file : files) {
            // 为每个文件创建一个 CompletableFuture
            CompletableFuture<Void> fileFuture = CompletableFuture.runAsync(() -> {
                final String fileId;
                try {
                    // 优化 MD5 计算，避免读取整个文件到内存
                    fileId = DigestUtils.md5DigestAsHex(new FileInputStream(file));
                    log.info("开始处理文件: {} (FileId: {})", file.getName(), fileId);
                } catch (IOException e) {
                    log.error("生成文件 {} 的MD5失败", file.getName(), e);
                    return; // 跳过此文件
                }
                // 检查文件是否正在处理中或已处理完成，使用 RedisMetadataService
                try {
                    Object status = redisMetadataService.getFileStatus(fileId);
                    if (("PROCESSING".equals(status) || "COMPLETED".equals(status))) {
                        log.info("文件 {} (FileId: {}) 已标记为 {} 状态，跳过处理.", file.getName(), fileId, status);
                        return;
                    }

                    // 标记文件为处理中，使用 RedisMetadataService
                    redisMetadataService.markFileProcessing(fileId);

                } catch (Exception e) {
                    log.error("读取或写入文件 {} (FileId: {}) 的 Redis 状态失败，跳过处理.", file.getName(), fileId, e);
                    return; // Redis 异常时跳过当前文件
                }

                // 第一次读取 sheet 列表
                // 使用 try-with-resources,资源不会抛出受检查异常,可以不写catch
                List<ReadSheet> sheets;
                try (ExcelReader reader = EasyExcel.read(file).build()) {
                    sheets = reader.excelExecutor().sheetList();
                    log.debug("文件 {} (FileId: {}) 包含 {} 个 Sheet.", file.getName(), fileId, sheets.size());
                } catch (Exception e) {
                    log.error("读取文件 {} Sheet 列表失败.", file.getName(), e);
                    return; // 读取 sheet 列表失败，跳过此文件
                }
                List<CompletableFuture<Void>> sheetFutures = new ArrayList<>(); // 用于存储每个 Sheet 解析任务的 CompletableFuture
                // 第二次用于实际读取(新的reader)
                for (ReadSheet sheet : sheets) {
                    if (sheet == null || sheet.getSheetName() == null) {
                        log.warn("文件 {} (FileId: {}) 发现空的 Sheet 定义，跳过.", file.getName(), fileId);
                        continue;
                    }
                    log.debug("开始处理文件 {} (FileId: {}) 中的 Sheet: {}", file.getName(), fileId, sheet.getSheetName());
                    // 为每个 Sheet 创建一个 CompletableFuture
                    CompletableFuture<Void> sheetFuture = CompletableFuture.runAsync(() -> {
                        // 创建监听器，传入所需服务
                        ReadListener<Student> listener = new ExcelUtil(
                                sheet.getSheetName(),
                                file.getAbsolutePath(),
                                redisMetadataService,
                                rabbitMQProducerService,
                                fileId
                        );

                        try {
                            EasyExcel.read(file, Student.class, listener)
                                    .headRowNumber(5)
                                    .sheet(sheet.getSheetNo())
                                    .doRead();
                            log.debug("文件 {} (FileId: {}) 中 Sheet {} 解析完成.", file.getName(), fileId, sheet.getSheetName());
                        } catch (Exception e) {
                            log.error("读取文件 {} (FileId: {}) 中 Sheet {} 失败.", file.getName(), fileId, sheet.getSheetName(), e);
                        }

                    }, taskExecutor);
                    sheetFutures.add(sheetFuture);
                }
                // 等待当前文件的所有 Sheet 解析完成
                CompletableFuture.allOf(sheetFutures.toArray(new CompletableFuture[0])).join();
                log.info("文件 {} (FileId: {}) 所有 Sheet 解析及数据存储/触发消息发送完成.", file.getName(), fileId);

            }, taskExecutor);
            fileFutures.add(fileFuture);
        }
        // 等待所有文件处理完成
        CompletableFuture.allOf(fileFutures.toArray(new CompletableFuture[0])).join();

        long endTime = System.currentTimeMillis();
        log.info("所有 Excel 文件解析 & 发送完成，总耗时: {} ms", endTime - startTime);
    }
}
